基于STM32的ADC应用实例(单通道、多通道、基于DMA) 您所在的位置:网站首页 channel firms什么意思 基于STM32的ADC应用实例(单通道、多通道、基于DMA)

基于STM32的ADC应用实例(单通道、多通道、基于DMA)

2024-04-08 05:26| 来源: 网络整理| 查看: 265

硬件:STM32F103ZET6 开发工具:Keil uVision5 下载调试工具:ARM仿真器(ST-Link)

 

 一、硬件部分

所用的芯片内嵌3个12位的模拟/数字转换器(ADC),每个ADC共用多达16个外部通道,2个内部通道。如下图所示:

 

 

 

ADC就是一个转换器,可以把模拟量和数字量进行互相转换,在这里演示的是把模拟量转化为数字量,就像一个重力秤,一个多重的人或者物件在上面都有一个对应重量的数值,ADC与重力秤差不多,不过它是把模拟量(温度、电压)转化为数字量,数字量可以是一个浮点型数据、整型数据、数组数据等。

在这里,ADC怎么把电压转换为数字量呢?

ADC内部可以采集0~3.3V的电压,采集的电压为0时,里面的刻度会显示是0,当采集的电压是3.3V时,里面的刻度会显示是4095(即满值)。

模拟/数字转换器(ADC)的分辨率、采样精度:12位。先来看看二进制的12位可表示0-4095个数,也就是说转换器通过采集转换所得到的最大值是4095,如:“111111111111”=4095,那么我们怎么通过转换器转换出来的值得到实际的电压值呢?如果我们要转换的电压范围是0v-3.3v的话,转换器就会把0v-3.3v平均分成4096份。设转换器所得到的值为x,所求电压值为y。那么就有:

 

讲完ADC采集数值为啥要(乘以3.3除以4096)之后,接下来将一下一个AD为啥可以分成多个通道同时C采集电压呢?

16个外部通道:简单的说就是芯片上有16个引脚是可以接到模拟电压上进行电压值检测的。16个通道不是独立的分配给3个转换器(ADC1、ADC2、ADC3)使用,有些通道是被多个转换器共用的。一个ADC的多个通道同时采集时,会有内部的转换机制进行分配优先顺序以及转换时间。

void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime) ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_239Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_239Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_239Cycles5);

其中第一行是STM公司提供的源代码,第2~第4行是示范。

ADCx指的是哪个ADC(ADC1、ADC2、ADC3都可以) ADC_Channel指的是指定ADC的规则组通道(如示范中的ADC_Channel_0,ADC_Channel_1,ADC_Channel_2) Rank指的是转换顺序(可分为序列1~序列16,数字越大优先顺序越后) ADC_SampleTime指的是转换的时间(一般采用的是ADC_SampleTime_239Cycles5)  

接下来,就是很多人比较困惑的地方,为啥ADC可以有多个采集通道?

因为一个ADC就是一个工具,对这个工具有使用权的都可以使用它,要看谁有使用权,就得看PCB原理图,如下所示。同时每个有使用权的通道要使用它,也不是同时使用的,因为一个ADC在同一时间只能有一个通道使用,优先级高的通道就可以优先使用它,具有同样优先权的通道,就由MCU进行自主分配。

其实一般我们可以通过上述的ADC通道配置函数进行配置:

void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime) Rank指的是转换顺序(可分为序列1~序列16,数字越大优先级越低)

ADC123_IN1:字母“ADC”不用多说,“123”代表它被3个(ADC1、ADC2、ADC3)转换器共用的引脚,“IN0”对应刚才那张宏定义图里面的ADC_Channel_0,这样就能找到每个通道对应的引脚了。

二、软件代码

普通模式的多通道

#include "adc.h" #include "delay.h" //初始化ADC //这里我们仅以规则通道为例 //我们默认将开启通道0~3 void Adc_Init(void) { ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE ); //使能ADC1通道时钟 RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M //PA1 作为模拟通道输入引脚 GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚 GPIO_Init(GPIOA, &GPIO_InitStructure); ADC_DeInit(ADC1); //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式 ADC_InitStructure.ADC_ScanConvMode = ENABLE; //模数转换工作在单通道模式 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //模数转换工作在单次转换模式 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐 ADC_InitStructure.ADC_NbrOfChannel = 3; //顺序进行规则转换的ADC通道的数目 ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器 ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1 ADC_ResetCalibration(ADC1); //使能复位校准 while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束 ADC_StartCalibration(ADC1); //开启AD校准 while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束 } //获得ADC值 //ch:通道值 0~3 u16 Get_Adc(u8 ch) { //设置指定ADC的规则组通道,一个序列,采样时间 ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道,采样时间为239.5周期 ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能 while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束 return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果 } u16 Get_Adc_Average(u8 ch,u8 times) //求多次采集数值的平均值 { u32 temp_val=0; u8 t; for(t=0;tDR; DMA_InitType.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; DMA_InitType.DMA_PeripheralInc=DMA_PeripheralInc_Disable; DMA_InitType.DMA_Priority=DMA_Priority_High; DMA_Init(DMA1_Channel1,&DMA_InitType); }

 

#include "led.h" #include "delay.h" #include "key.h" #include "sys.h" #include "lcd.h" #include "usart.h" #include "adc.h" #include "dma.h" /* ADC以及DMA的定义 */ #define N 10 //10次 #define M 3 //3个ADC通道 extern u16 AD_Value[N][M]; extern float After_filter[M]; int main(void) { float value[M]; u16 adcx; u8 i=0; float temp; delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级 uart_init(115200); //串口初始化为115200 LED_Init(); //LED端口初始化 Adc_Init(); Dma_Init(); ADC_SoftwareStartConvCmd(ADC1,ENABLE); DMA_Cmd(DMA1_Channel1,ENABLE); while(1) { while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); filter(); for(i=0;i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有